<?php

namespace App\Traits\Authorization;

use Betterde\Tree\Generator;
use Carbon\Carbon;
use App\Models\Company;
use App\Models\Attendance;
use App\Package\Tree\Tree;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use App\Repositories\AttendanceRepository;

trait Strategy
{
	/**
	 * 验证用户是否属于某个公司
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @param int|null $id
	 * @return bool
	 */
	public function memberOfCompany(int $id = null): bool
	{
		if ($this->hasCompany()) {
			return $this->company_id === $id;
		}
		return false;
	}

	/**
	 * 判断用户是否有归属公司
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @return bool
	 */
	public function hasCompany(): bool
	{
		return ! is_null($this->company_id);
	}

	/**
	 * 判断用户是否拥有指定项目
	 *
	 * Date: 16/04/2018
	 * @author George
	 * @param int $project_id
	 * @return bool
	 */
	public function hasProject(int $project_id): bool
	{
		$projects = $this->getProjects();

		if ($projects->isEmpty()) {
			return false;
		}

		return $projects->contains($project_id);
	}

	/**
	 * 验证用户是否属于某个项目
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @param int $project
	 * @return bool
	 */
	public function memberOfProject(int $project): bool
	{
		$projects = $this->projects()->where('start', '<', Carbon::now())->where('end', '>', Carbon::now())->pluck('projects.id');
		return $projects->contains($project);
	}

	/**
	 * 获取指定日期的考勤记录
	 *
	 * Date: 17/04/2018
	 * @author George
	 * @param bool $date
	 * @return Attendance
	 * @throws \App\Exceptions\GeneralException
	 */
	public function getAttendance($date = false)
	{
		$attendanceRepository = new AttendanceRepository();
		return $attendanceRepository->getByUser($this->id, $date);
	}

	/**
	 * 验证用户是否是管理员，并拥有指定模块的权限
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @param string $code
	 * @return mixed
	 */
	public function hasModule(string $code): bool
	{
		if ($this->isManager() && $this->memberOfCompany()) {
			$modules = Cache::rememberForever("companies:$this->company_id:modules", function () {
				return $this->company->modules()->pluck('code');
			});
			return $modules->contains($code);
		}
		return false;
	}

	/**
	 * 验证用户是否分配岗位或是否隶属于某个岗位
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @param int|null $id
	 * @return bool
	 */
	public function hasPosition(int $id = null): bool
	{
		if (is_null($this->position_id)) {
			return false;
		} else {
			return $this->position_id === $id;
		}
	}

	/**
	 * 验证用户是否拥有某项权限
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @param string $code
	 * @return bool
	 */
	public function hasPermission(string $code): bool
	{
		if ($this->hasPosition()) {
			$permissions = Cache::remember("users:$this->id:permissions", 10, function () {
				return $this->position->permissions()->pluck('code');
			});
			return $permissions->contains($code);
		}
	}

	/**
	 * 验证用户是否是公司后台管理员
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @return bool
	 */
	public function isManager(): bool
	{
		return (boolean) $this->manager;
	}

    /**
     * 获取用户的排班信息
     *
     * Date: 22/04/2018
     * @author George
     * @param string $type
     * @param bool $date
     * @return mixed
     */
	public function getSchedule($type = 'checkin', $date = false)
	{
        $date = $date ? $date : date('Y-m-d');
        if ($type === 'checkin') {
            return $this->schedules()->with('attendance', 'project')->whereDate('start_timestamp', $date)->first();
        }

        $schedule = $this->schedules()->with('attendance', 'project')->whereDate('end_timestamp', $date)->first();

        if (! $schedule) {
        	$schedule = $this->schedules()->with('attendance', 'project')->whereDate('start_timestamp', $date)->first();
		}

		return $schedule;
	}

	/**
	 * 获取公司信息
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @return Company
	 */
	public function getCompany()
	{
		return $this->company = $this->company()->first();
	}

	/**
	 * 获取用户的项目
	 *
	 * Date: 16/04/2018
	 * @author George
	 * @return Collection
	 */
	public function getProjects(): Collection
	{
		/**
		 * @var Collection $projects
		 */
		$projects = $this->projects()->select('projects.id')->get()->pluck('id');

		// 判断用户是否有主项目
		if (!$this->project) {
			return $projects;
		}

		// 判断用户项目列表中是否含有主项目ID
		if (!$projects->contains($this->project->id)) {
			$projects->push($this->project->id);
		}

		return $projects;
	}

	/**
	 * 获取公司模块信息
	 *
	 * Date: 25/03/2018
	 * @author George
	 * @return Collection
	 * @throws \App\Exceptions\GeneralException
	 */
	public function getModules()
	{
		$modules = [];
		if ($this->hasCompany()) {
			$codes = Cache::rememberForever("companies:$this->company_id:modules", function () {
				return $this->company->modules()->pluck('code');
			});
			foreach ($codes as $code) {
				$modules[] = Cache::rememberForever("modules:$code", function () use ($code) {
					return DB::table('modules')->select([
						'code', 'parent_code', 'name',
						'introduction', 'pricing', 'icon',
						'cover', 'status', 'type', 'order'
					])->where('code', $code)->first();
				});
			}
		}
		$generator = new Tree();
		$tree = $generator->make(collect($modules)->sortBy('order'), 'code', 'parent_code', 'children', '');
		return $this->modules = $tree;
	}

	/**
	 * 获取用户部门
	 *
	 * Date: 29/04/2018
	 * @author George
	 * @return mixed
	 */
	public function getDepartment()
	{
		return $this->departments = $this->department()->first();
	}

	/**
	 * 获取用户岗位
	 *
	 * Date: 29/04/2018
	 * @author George
	 * @return mixed
	 */
	public function getPosition()
	{
		return $this->position = $this->position()->first();
	}

	/**
	 * 获取用户
	 *
	 * Date: 25/03/2018
	 * @author George
	 */
	public function getPermissions()
	{
		$permissions = collect([]);
		if ($this->hasPosition()) {
			$permissions = Cache::remember("users:$this->id:permissions", 10, function () {
				return $this->position->permissions()->pluck('code');
			});
		}
		return $this->permissions = $permissions;
	}

	/**
	 * 获取用户的菜单
	 *
	 * Date: 29/04/2018
	 * @author George
	 * @param bool $recursion
	 * @return array|Collection|mixed
	 * @throws \Betterde\Tree\Exceptions\TreeException
	 */
	public function getMenus($recursion = false)
	{
		// 获取岗位信息
		$position = $this->position()->with(['permissions.permissiontable' => function ($query) {
			$query->where('status', 1);
		}])->first();

		if (! $position) {
			return [];
		}

		// 根据敢为获取菜单信息
		$menus = $position->permissions->pluck('permissiontable')->sortBy('sort');

		// 判断是否需要生成树型结构
		if ($recursion) {
			$tree = new Generator();
			return $this->menus = $tree->make(collect($menus), 'code', 'parent_code', 'children', 'top');
		}

		return $this->menus = $menus;
	}
}
